package edu.gatech.cs6330.client;

import java.util.Vector;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.XMLParser;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class SearchRSS implements EntryPoint {

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {

		posts = new Vector<RSSPost>();
		
		Panel formPanel = formPanel();

		// Add image and button to the RootPanel
		RootPanel.get().add(formPanel);

	}

	public Panel formPanel() {

		Label instructions = new Label(
				"Please enter a list of feeds in OPML format, and a string to search for:");

		feeds = new TextArea();
		feeds.setCharacterWidth(60);
		feeds.setVisibleLines(20);

		search = new TextBox();

		Button button = new Button("Search My Feeds!");

		VerticalPanel vPanel = new VerticalPanel();
		// We can add style names.
		vPanel.addStyleName("widePanel");
		vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
		vPanel.add(instructions);
		vPanel.add(feeds);
		vPanel.add(search);
		vPanel.add(button);

		button.addClickListener(new ClickListener() {
			public void onClick(Widget sender) {
				Vector<String> feedURLs = getFeedURLs(feeds.getText());
				processFeeds(feedURLs);
			}
		});

		return vPanel;
	}
	
	public void showResults()
	{
		RootPanel.get().clear();
		RootPanel.get().add(resultsPanel());
	}
	
	public Panel resultsPanel() 
	{
		Panel results = new VerticalPanel();
		for(int i = 0 ; i < posts.size(); ++i) {
			RSSPost p = (RSSPost) posts.get(0);
			HTML item = new HTML(p.title + " - <a href = \"" + p.url + "\">" + p.url + "</a>");
			results.add(item);
		}
		return results;
	}
	
	public Vector<String> getFeedURLs(String opmlText) {
		Document dom = XMLParser.parse(opmlText);
		Element root = dom.getDocumentElement();
		// Must do this if you ever use a raw node list that you expect to be
		// all elements.
		XMLParser.removeWhitespace(root);
		Node body = root.getElementsByTagName("body").item(0);
		NodeList feeds = body.getChildNodes();
		Vector<String> urls = new Vector<String>();
		for (int i = 0; i < feeds.getLength(); ++i) {
			Element feed = (Element) feeds.item(i);
			String url = feed.getAttribute("xmlUrl");
			urls.add(url);
		}
		return urls;
	}

	public void processFeeds(Vector<String> feeds) {
		for (int i = 0; i < feeds.size(); ++i) {
			processFeed(feeds.get(i));
		}
	}

	public void processFeed(String feed) {
		RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET,
				feed);
		try {
			requestBuilder.sendRequest(null, new RequestCallback() {
				public void onError(Request request, Throwable exception) {
					requestFailed(exception);
				}

				public void onResponseReceived(Request request,
						Response response) {
					processFeedXML(response.getText());
				}
			});
		} catch (RequestException ex) {
			requestFailed(ex);
		}

	}

	private void requestFailed(Throwable exception) {
		Window.alert("Failed to send the request.  The error message was: "
				+ exception.getMessage());
	}

	public class RSSPost {
		public String url;
		public String title;
	}

	public void processFeedXML(String feed) {
		Document dom = XMLParser.parse(feed);
		Element root = dom.getDocumentElement();
		// Must do this if you ever use a raw node list that you expect to be
		// all elements.
		XMLParser.removeWhitespace(root);
		NodeList entries = root.getElementsByTagName("entry");
		for (int i = 0; i < entries.getLength(); ++i) {
			Element entry = (Element) entries.item(i);
			Node id = entry.getElementsByTagName("id").item(0);
			String url = id.getFirstChild().getNodeValue();
			Node titleNode = entry.getElementsByTagName("title").item(0);
			String title = titleNode.getFirstChild().getNodeValue();
			RSSPost post = new RSSPost();
			post.url = url;
			post.title = title;
			processPost(post);
		}
	}

	public class PostRequestCallback implements RequestCallback {
		
		public PostRequestCallback(RSSPost p) {
			post = p;
		}
		
		public void onError(Request request, Throwable exception) {
			requestFailed(exception);
		}

		public void onResponseReceived(Request request,
				Response response) {
			if (response.getText().contains(search.getText())) {
				posts.add(post);
				showResults();
			}
		}
		
		private RSSPost post;
	}
	
	public void processPost(RSSPost post) {
		if(post.url == null) return;
		RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET,
				post.url);
		try {
			PostRequestCallback callback = new PostRequestCallback(post);
			requestBuilder.sendRequest(null, callback);
			
		} catch (RequestException ex) {
			requestFailed(ex);
		}
	}

	private TextArea feeds;
	private TextBox search;
	private Vector<RSSPost> posts;

}
